package kubernetes

import (
	"fmt"

	"golang.org/x/net/context"
	v1beta1 "k8s.io/api/extensions/v1beta1"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

var IngressWrap ingresswrap = ingresswrap{}

type ingresswrap struct{}

func (ingresswrap) List(namespace string) (*v1beta1.IngressList, error) {
	return clientset.ExtensionsV1beta1().Ingresses(namespace).List(context.Background(), metav1.ListOptions{})
}

func (ingresswrap) Get(namespace, name string) (*v1beta1.Ingress, error) {
	return clientset.ExtensionsV1beta1().Ingresses(namespace).Get(context.Background(), name, metav1.GetOptions{})
}

func (ingresswrap) Delete(namespace, name string) error {
	return clientset.ExtensionsV1beta1().Ingresses(namespace).Delete(context.Background(), name, metav1.DeleteOptions{})
}

type ingressAssemble struct {
	namespace   string
	name        string
	annotations map[string]string
	// rules       []v1beta1.IngressRule
	ingressPaths []v1beta1.HTTPIngressPath
}

func NewIngressAssemble(namespace, name string) ingressAssemble {
	return ingressAssemble{
		namespace: namespace,
		name:      name,
		annotations: map[string]string{
			"kubernetes.io/ingress.class":                "nginx",
			"nginx.ingress.kubernetes.io/ssl-redirect":   "false",
			"nginx.ingress.kubernetes.io/rewrite-target": "/$2", // 重写uri，避免ingress的路径前缀被带到svc和pod，组合rule:path的(/|$)(.*)使用
		},
		ingressPaths: []v1beta1.HTTPIngressPath{},
	}
}

func (ia ingressAssemble) Annotation(k, v string) ingressAssemble {
	a := ia.annotations
	a[k] = v
	ia.annotations = a
	return ia
}

func (ia ingressAssemble) Rule(path string, backendSvcName string, backendSvcPort int32) ingressAssemble {
	pt := v1beta1.PathTypePrefix
	hip := v1beta1.HTTPIngressPath{
		PathType: &pt,
		Path:     fmt.Sprintf("%s%s", path, "(/|$)(.*)"), // 重写uri，避免ingress的路径前缀被带到svc和pod
		Backend: v1beta1.IngressBackend{
			ServiceName: backendSvcName,
			ServicePort: intstr.IntOrString{Type: intstr.Int, IntVal: backendSvcPort},
		},
	}
	ia.ingressPaths = append(ia.ingressPaths, hip)
	return ia
}

func (ia ingressAssemble) Create() (*v1beta1.Ingress, error) {
	ingress := &v1beta1.Ingress{
		TypeMeta:   metav1.TypeMeta{Kind: "Ingress", APIVersion: "v1"},
		ObjectMeta: metav1.ObjectMeta{Namespace: ia.namespace, Name: ia.name, Annotations: ia.annotations},
		Spec: v1beta1.IngressSpec{
			Rules: []v1beta1.IngressRule{
				{
					IngressRuleValue: v1beta1.IngressRuleValue{
						HTTP: &v1beta1.HTTPIngressRuleValue{
							Paths: ia.ingressPaths,
						},
					},
				},
			},
		},
	}
	return clientset.ExtensionsV1beta1().Ingresses(ia.namespace).Create(context.Background(), ingress, metav1.CreateOptions{})
}
